import os
import shutil
import codecs
from openpyxl import load_workbook
from openpyxl.worksheet.table import Table
from openpyxl.styles import Alignment
from enum import Enum, auto
from datetime import datetime

# Define file info structure
class can_file_info:
    def __init__(self, cover_name, rm_rev, rm_date, rm_author, rm_change_comment, can_tag):
        self.cover_name = cover_name
        self.rm_rev = rm_rev
        self.rm_date = rm_date
        self.rm_author = rm_author
        self.rm_change_comment = rm_change_comment
        self.can_tag = can_tag

# Define struct
class Controller(Enum):
    CanController_BCAN = 0          # BCAN
    CanController_CCAN = auto()     # CCAN
    CanController_PCAN = auto()     # PCAN
    CanController_ACAN = auto()     # ADBCANFD
    CanController_DCAN = auto()     # OBDCAN
    CanController_CAN5 = auto()
# class Controller(Enum):
#     CanController_CAN0 = 2          # BCAN
#     CanController_CAN1 = 1     # CCAN
#     CanController_CAN2 = 0     # PCAN
#     CanController_CAN3 = 3     # ADBCANFD
#     CanController_CAN4 = 4     # OBDCAN

# Define global dictionary of file information
g_can_file_info = {
    Controller.CanController_ACAN: can_file_info("", "", "", "", "", ""),
    Controller.CanController_BCAN: can_file_info("", "", "", "", "", ""),
    Controller.CanController_CCAN: can_file_info("", "", "", "", "", ""),
    Controller.CanController_PCAN: can_file_info("", "", "", "", "", "")
}

# Define communication matrix structure
# The time is in milliseconds
class can_comm_matrix_t:
    def __init__(self, msg_name, msg_type, msg_id, send_type, cycle_time, frame_format, brs, msg_length, fast_cycle, fast_nr, msg_delay, direction):
        self.msg_name = msg_name            # Msg Name
        self.msg_type = msg_type            # Msg Type: Normal, NM, Diag
        self.msg_id = msg_id                # Message Identifier
        self.send_type = send_type          # Send type:"Cycle", "Event", "IfActive", "CE" and "CA
        self.cycle_time = cycle_time        # Msg Cycle Time
        self.frame_format = frame_format    # Extended or Standard
        self.brs = brs                      # 
        self.msg_length = msg_length        # Byte length of the message
        self.fast_cycle = fast_cycle        # Msg Cycle Time Fast: The fast cycle time of message if  the Msg Send Type of message is not "Cycle"
        self.fast_nr = fast_nr              # Msg Nr. Of Reption: The reption number of message if  the Msg Send Type of message is not "Cycle"
        self.msg_delay = msg_delay          # Msg Delay Time(ms): The min time between the same ID message if  the Msg Send Type of message is not "Cycle"
        self.direction = direction          # S: Send, R: Receive

# Define global dictionary of communication matrix
g_can_comm_matrix = {
    Controller.CanController_BCAN: [],
    Controller.CanController_CCAN: [],
    Controller.CanController_PCAN: [],
    Controller.CanController_ACAN: []
}

g_can_fbcm_obj = {
    Controller.CanController_BCAN: "FBCM_BCAN_OBJ",
    Controller.CanController_CCAN: "FBCM_CCAN_OBJ",
    Controller.CanController_PCAN: "FBCM_PCAN_OBJ",
    Controller.CanController_ACAN: "FBCM_ACAN_OBJ"
}

g_matrix_path = "./matrix_files"
g_generated_path = "./generated"
g_rte_path = g_generated_path + "/rte"
g_can_common_text_front = """/*
 * This file is automatically generated and does not allow modification!
 *
 * This file is the common header file of CAN communication.
 * Author: GangSongSong
 * Date: {ddd2}
 */
#ifndef RTE_CAN_COMMON_H
#define RTE_CAN_COMMON_H

#include "Platform_Types.h"

#ifndef  _CAN_MESSAGE_BUS_
#define  _CAN_MESSAGE_BUS_
typedef struct {{
    uint8_t Extended;
    uint8_t Length;
    uint8_t Remote;
    uint8_t Error;
    uint32_t ID;
    double Timestamp;
    uint8_t Data[8];
}} CAN_MESSAGE_BUS;
#endif

typedef struct {{
    uint8_t ProtocolMode;
    uint8_t Extended;
    uint8_t Length;
    uint8_t Remote;
    uint8_t Error;
    uint8_t BRS;
    uint8_t ESI;
    uint8_t DLC;
    uint32_t ID;
    uint32_t Reserved;
    double Timestamp;
    uint8_t Data[64];
}} CAN_FD_MESSAGE_BUS;

#endif  /* RTE_CAN_COMMON_H */
"""

g_can_rte_header_text_front = """/*
 * This file is automatically generated and does not allow modification!
 * Can Communication Matrix basic information
 * File name: {name}
 * Revision: {rev}, Date: {ddd1}
 * Change Comment: {comment}
 *
 * Author: GangSongSong
 * Date: {ddd2}
 */
#ifndef RTE_{can_tag}_H
#define RTE_{can_tag}_H

#include "Rte_Can_Common.h"

/**
* FBCM RTE Naming Rule: Msg Name + {can_tag}
*/
"""

g_can_rte_header_text_back = """
#endif  /* RTE_{can_tag}_H */
"""

g_can_rte_c_text_front = """/*
 * This file is automatically generated and does not allow modification!
 * Can Communication Matrix basic information
 * File name: {name}
 * Revision: {rev}, Date: {ddd1}
 * Change Comment: {comment}
 *
 * Author: GangSongSong
 * Date: {ddd2}
 */

#include "Rte_{can_tag}.h"

/**
* FBCM RTE Naming Rule: Msg Name + {can_tag}
*/
"""

g_can_handle_h_text_front = """/*
 * This file is automatically generated and does not allow modification!
 *
 * This file is the can handle header file of CAN communication.
 * Author: GangSongSong
 * Date: {ddd2}
 */
#ifndef CAN_HANDLE_H_
#define CAN_HANDLE_H_

#include "can.h"

/**
 * @description: The received data is padded to the rte.
 * @param {{uint32}} can_id
 * @param {{uint8}} dlc
 * @param {{uint8}} *psrc
 * @return {{*}}
 */
extern void can_report_handle(const uint8 cntr, const uint32 can_id, const uint8 dlc, const uint8 *psrc);

#endif /* CAN_HANDLE_H_ */
"""

g_can_handle_c_text_front = """/*
 * This file is automatically generated and does not allow modification!
 *
 * This file is the can handle file of CAN communication.
 * Author: GangSongSong
 * Date: {ddd2}
 */
#include "can.h"
#include "string.h"
#include "rte.h"
#include "can_handle.h"
#include "can_table.h"
#include "app_AUTOSAR_NM_CAN.h"
#include "UDS_config.h"

/**
 * @description: The received data is padded to the rte.
 * @param {{uint32}} can_id
 * @param {{uint8}} dlc
 * @param {{uint8}} *psrc
 * @return {{*}}
 */
void can_report_handle(const uint8 cntr, const uint32 can_id, const uint8 dlc, const uint8 *psrc)
{{
    switch(can_id) {{
"""

g_can_handle_c_text_back = """        default:
        break;
    }
}
"""

g_can_send_table_h_text_front = """/*
 * This file is automatically generated and does not allow modification!
 *
 * This file is the can send table file of CAN communication.
 * Author: GangSongSong
 * Date: {ddd2}
 */
#ifndef CAN_TABLE_H_
#define CAN_TABLE_H_

#include "can.h"

#define FBCM_BCAN_OBJ CanHardwareObject_CAN0_TX
#define FBCM_CCAN_OBJ CanHardwareObject_CAN1_TX
#define FBCM_PCAN_OBJ CanHardwareObject_CAN2_TX
#define FBCM_ACAN_OBJ CanHardwareObject_CAN3_TX     // ADBCANFD
#define FBCM_DCAN_OBJ CanHardwareObject_CAN4_TX     // OBD

#define CAN_CYCLE_SEND_10MS_TABLE_COUNT  {cycle_10ms_count}
#define CAN_CYCLE_SEND_100MS_TABLE_COUNT {cycle_100ms_count}
#define CAN_CONDITION_SEND_TABLE_COUNT   {condition_count}

#define CAN_CONDITION_SEND_MIN_TIME_INTERVAL    20  /* Minimum time interval 20ms */

typedef enum _cc{{
    CAN_MESSAGE_NO_CHECK,
    CAN_MESSAGE_NEED_CRC8,
    CAN_MESSAGE_NEED_CRC16,
}}can_message_check_e;

typedef enum _st{{
    CAN_MESSAGE_SEND_TYPE_CYCLE,
    CAN_MESSAGE_SEND_TYPE_EVENT,
    CAN_MESSAGE_SEND_TYPE_CE,
    CAN_MESSAGE_SEND_TYPE_IFACTIVE,
    CAN_MESSAGE_SEND_TYPE_CA
}}can_message_send_type_e;

typedef struct _ccst
{{
    uint32 can_id;
    Can_HwHandleType Hth;
    uint64 send_time;
    uint32 cycle_time;
    uint8 dlc;
    uint8 *psrc;
}}can_cycle_s_table_t;

typedef struct _ccst1
{{
    uint32 can_id;
    Can_HwHandleType Hth;
    uint64 send_time;
    uint32 cycle_time;
    uint32 fast_cycle;
    can_message_send_type_e st;
    volatile boolean *condition;
    uint8 fast_nr;      /* fast send number */
    uint8 fast_s_c;     /* fast send count */
    boolean fast_flg;   /* fast send flag */
    uint8 msg_delay;
    uint8 dlc;
    uint8 *psrc;
}}can_condition_s_table_t;

extern can_cycle_s_table_t can_cycle_s_10ms_table[];
extern can_cycle_s_table_t can_cycle_s_100ms_table[];

extern can_condition_s_table_t can_condition_s_table[];

#endif /* CAN_TABLE_H_ */
"""

g_can_send_table_c_text_front = """/*
 * This file is automatically generated and does not allow modification!
 *
 * This file is the can send table file of CAN communication.
 * Author: GangSongSong
 * Date: {ddd2}
 */
#include "string.h"
#include "rte.h"
#include "can_table.h"

"""

# Get Excel file information
def get_can_file_info(wb, Controller):
    active_sheet = wb.active
    # print(type(active_sheet))
    # print(wb.sheetnames)

    # Read Cover sheet
    ws = wb["Cover"]
    g_can_file_info[Controller].cover_name = ws['B6'].value
    # If the cell has content, remove the line break and combine it into one line
    # Check if the cell has rich text
    if hasattr(g_can_file_info[Controller].cover_name, 'rich_text') and g_can_file_info[Controller].cover_name.rich_text:
        # Traverse all paragraphs in rich text
        for i, paragraph in enumerate(g_can_file_info[Controller].cover_name.rich_text.paragraphs):
            # Delete line breaks and set new text
            g_can_file_info[Controller].cover_name.rich_text.paragraphs[i].text = paragraph.text.replace('\n', ' ')
    else:
        # If the cell does not have rich text, set the text directly
        g_can_file_info[Controller].cover_name = g_can_file_info[Controller].cover_name.replace('\n', ' ')

    print(g_can_file_info[Controller].cover_name)

    # Read version information
    ws = wb["History"]
    for row in ws.iter_rows(min_row=3, values_only=True):
        if row[0] == None:
            continue
        g_can_file_info[Controller].rm_rev = row[0]
        g_can_file_info[Controller].rm_date = row[1]
        g_can_file_info[Controller].rm_author = row[2]
        g_can_file_info[Controller].rm_change_comment = row[6]
    print(g_can_file_info[Controller].rm_rev, g_can_file_info[Controller].rm_date, g_can_file_info[Controller].rm_author, g_can_file_info[Controller].rm_change_comment)

# Get CAN Communication Matrix Data
def get_can_comm_matrix_data(wb, Controller):
    # Get sheet
    ws = wb["Matrix"]
    # print("We will read sheet:", ws.title)

    for row in ws.iter_rows(min_row=2, values_only=True):
        if row[0] == None:
            continue
        g_can_comm_matrix[Controller].append(can_comm_matrix_t(row[0], row[1], row[2], row[4], row[5], row[6], row[7], row[8], row[31], row[32], row[33], row[34]))

    # print(g_can_comm_matrix[Controller].__len__())
    # for content in g_can_comm_matrix[Controller]:
    #     print(content.msg_name, content.msg_type, content.msg_id, content.send_type, content.cycle_time, \
    #           content.frame_format, content.brs, content.msg_length, \
    #             content.fast_cycle, content.fast_nr, content.msg_delay, content.direction)

# Generate CAN Communication Matrix Rte files
def generate_can_commm_matrix_rte(Controller):
    rte_headler = g_rte_path + "/inc/" + "Rte_" + g_can_file_info[Controller].can_tag + ".h"
    rte_c_file = g_rte_path + "/src/" + "Rte_" + g_can_file_info[Controller].can_tag + ".c"

    rte_h_rte_contents = []
    rte_c_rte_contents = []
    # ACan is the CanFd.
    if Controller.CanController_ACAN == Controller:
        for message in g_can_comm_matrix[Controller]:
            # When message type is Diag or NM, we do not need to generate Rte variable.
            # We will handle in the report table(def generate_can_matrix_report_table).
            if "Diag" == message.msg_type or "NM" == message.msg_type:
                continue
            rte_h_rte_contents.append("extern CAN_FD_MESSAGE_BUS " + message.msg_name + "_" + g_can_file_info[Controller].can_tag + ";\n")
            rte_c_rte_contents.append("CAN_FD_MESSAGE_BUS " + message.msg_name + "_" + g_can_file_info[Controller].can_tag + ";\n")
    else:
        for message in g_can_comm_matrix[Controller]:
            if "FBCM_EC" == message.msg_name:
                print(f"RTE_H: {message.msg_name} is J1939 message in {Controller.name}, skip it")
                continue
            if "Diag" == message.msg_type or "NM" == message.msg_type:
                continue
            rte_h_rte_contents.append("extern CAN_MESSAGE_BUS " + message.msg_name + "_" + g_can_file_info[Controller].can_tag + ";\n")
            rte_c_rte_contents.append("CAN_MESSAGE_BUS " + message.msg_name + "_" + g_can_file_info[Controller].can_tag + ";\n")
    
    # Generate Rte Conditions
    if Controller.CanController_ACAN == Controller:
        for message in g_can_comm_matrix[Controller]:
            # When message type is Diag or NM, we do not need to generate Rte variable.
            # We will handle in the report table(def generate_can_matrix_report_table).
            if "Diag" == message.msg_type or "NM" == message.msg_type:
                continue
            if "Cycle" == message.send_type:
                continue
            rte_h_rte_contents.append("extern volatile boolean " + message.msg_name + "_" + g_can_file_info[Controller].can_tag + "_flag;\n")
            rte_c_rte_contents.append("volatile boolean " + message.msg_name + "_" + g_can_file_info[Controller].can_tag + "_flag = 0;\n")
    else:
        for message in g_can_comm_matrix[Controller]:
            if "FBCM_EC" == message.msg_name:
                print(f"RTE_C: {message.msg_name} is J1939 message in {Controller.name}, skip it")
                continue
            if "Diag" == message.msg_type or "NM" == message.msg_type:
                continue
            if "Cycle" == message.send_type or "R" == message.direction:
                continue
            rte_h_rte_contents.append("extern volatile boolean " + message.msg_name + "_" + g_can_file_info[Controller].can_tag + "_flag;\n")
            rte_c_rte_contents.append("volatile boolean " + message.msg_name + "_" + g_can_file_info[Controller].can_tag + "_flag = 0;\n")

    if Controller.CanController_CCAN == Controller:
        rte_h_rte_contents.append("extern uint8 FBCM_EC_CCAN[28];\n")
        rte_c_rte_contents.append("uint8 FBCM_EC_CCAN[28];\n")

    now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    # Generate Rte header file
    try:
        # In order to store gbk characters, we need to use codecs.open() instead of open().
        # And specify the encoding type as gbk.
        with codecs.open(rte_headler, 'w', 'gbk') as f:
            rte_headler_front_content = g_can_rte_header_text_front.format(
                name = g_can_file_info[Controller].cover_name,
                rev = g_can_file_info[Controller].rm_rev,
                ddd1 = g_can_file_info[Controller].rm_date,
                # author = g_can_file_info[Controller].rm_author,
                comment = g_can_file_info[Controller].rm_change_comment,
                ddd2 = now,
                can_tag = g_can_file_info[Controller].can_tag
            )
            f.write(rte_headler_front_content)
            rte_headler_back_content = g_can_rte_header_text_back.format(
                can_tag = g_can_file_info[Controller].can_tag
            )
            # Because the rte_h_rte_contents is a list, we need to use join() to combine the list into a string.
            f.write("".join(rte_h_rte_contents))
            f.write(rte_headler_back_content)
    except Exception as e:
        print("Error:", e)

    # Generate Rte c file
    try:
        with codecs.open(rte_c_file, "w", 'gbk') as f:
            rte_c_front_content = g_can_rte_c_text_front.format(
                name = g_can_file_info[Controller].cover_name,
                rev = g_can_file_info[Controller].rm_rev,
                ddd1 = g_can_file_info[Controller].rm_date,
                # author = g_can_file_info[Controller].rm_author,
                comment = g_can_file_info[Controller].rm_change_comment,
                ddd2 = now,
                can_tag = g_can_file_info[Controller].can_tag
            )
            f.write(rte_c_front_content)
            f.write("".join(rte_c_rte_contents))
                    
    except Exception as e:
        print("Error:", e)

# Parse CAN communication matrix file
def parse_can_commm_matrix_file(filename, Controller):
    if False == os.path.exists(filename):
        print(filename, "file not exists")
        return

    # Read excel file
    wb = load_workbook(filename, read_only=True)
    get_can_file_info(wb, Controller)
    get_can_comm_matrix_data(wb, Controller)
    generate_can_commm_matrix_rte(Controller)

# Generate CAN communication matrix report table
def generate_can_matrix_report_table():
    cntles = list(Controller)
    report_contents = []
    report_nm_contents = []
    report_diag_contents = []
    for cntle in cntles[:4]:
        for row in g_can_comm_matrix[cntle]:
            if "Normal" == row.msg_type and row.msg_id is not None and row.direction == "R":
                msg_id = row.msg_id.rstrip('x')
                report_content = """        case {id}:"""
                if "ExtendedCAN" == row.frame_format or "ExtendedCAN_FD" == row.frame_format:
                    report_content = report_content + """
            {rte_variable_f}_{rte_variable_b}.Extended = 1;"""
                else:
                    report_content = report_content + """
            {rte_variable_f}_{rte_variable_b}.Extended = 0;"""
                report_content = report_content + """
            {rte_variable_f}_{rte_variable_b}.Length = dlc;
            {rte_variable_f}_{rte_variable_b}.ID = can_id;
            memcpy({rte_variable_f}_{rte_variable_b}.Data, psrc, dlc);
        break;
"""
                report_contents.append(report_content.format(id = msg_id, rte_variable_f = row.msg_name, rte_variable_b = g_can_file_info[cntle].can_tag))
            # NM report table, see the following comment.
#             if "NM" == row.msg_type and row.msg_id is not None and row.direction == "R":
#                 msg_id = row.msg_id.rstrip('x')
#                 report_content = """        case {id}:
#             /* TODO: NM */
#         break;
# """
                # report_nm_contents.append(report_content.format(id = msg_id))
            # Diagnostic report table
            if "Diag" == row.msg_type and row.msg_id is not None and row.direction == "R":
                msg_id = row.msg_id.rstrip('x')
                report_content = """        case {id}:
"""
                report_diag_contents.append(report_content.format(id = msg_id))
    # Because the matrix file is not complete, we will generate the NM table
    # by the 0x18FFA000x - 0x0x18FFA0FFx in the specification(AUTOSAR NM design specification).
    report_nm_contents = """        case 0x18FFA000 ... 0x18FFA0FF:
            app_AUTOSAR_NM_CAN_feed_data(cntr, can_id, dlc, psrc);
        break;
"""
    report_contents += report_nm_contents
    # Because the matrix file is not complete, we will add the ExtFunc_DiagReq in the report table by the Routing Table.
    report_diag_contents.append("""        case 0x18DBFFFA:
            app_AUTOSAR_NM_CAN_feed_data(cntr, can_id, dlc, psrc);
            if(can_id==0x18DA27FA || can_id==0x18DBFFFA )
            {
                UDS_Interface_UDSonCAN_RX(cntr, can_id, dlc, psrc);
            }
        break;
""")
    report_contents += report_diag_contents
    # report_contents is a list, we need to combine the list into a string.
    final_report_content = "".join(report_contents)
    
    now_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    # Generate can_handle.h
    try:
        with open(g_generated_path + "/can_handle.h", 'w') as f:
            headle_content = g_can_handle_h_text_front.format(
                ddd2 = now_time
            )
            f.write(headle_content)
    except Exception as e:
        print("Error:", e)
    # Generate can_handle.c
    try:
        with open(g_generated_path + "/can_handle.c", 'w') as f:
            c_content = g_can_handle_c_text_front.format(
                ddd2 = now_time
            )
            f.write(c_content)
            f.write(final_report_content)
            f.write(g_can_handle_c_text_back)
    except Exception as e:
        print("Error:", e)

# Generate CAN communication matrix send table
def generate_can_matrix_send_table():
    cntles = list(Controller)
    send_contents = []
    send_10ms_content = []
    send_10ms_contents = []
    cycle_10ms_count = 0
    send_10ms_content_front = """can_cycle_s_table_t can_cycle_s_10ms_table[CAN_CYCLE_SEND_10MS_TABLE_COUNT] = {
"""
    send_100ms_content = []
    send_100ms_contents = []
    cycle_100ms_count = 0
    send_100ms_content_front = """can_cycle_s_table_t can_cycle_s_100ms_table[CAN_CYCLE_SEND_100MS_TABLE_COUNT] = {
"""
    send_condition_content = []
    send_condition_contents = []
    condition_count = 0
    send_condition_content_front = """can_condition_s_table_t can_condition_s_table[CAN_CONDITION_SEND_TABLE_COUNT] = {
"""
    send_content_back = """};
"""
    for cntlr in cntles[:4]:
        for row in g_can_comm_matrix[cntlr]:
            # J1939 skip it
            if "FBCM_EC" == row.msg_name:
                print(f"S_Table: {row.msg_name} is J1939 message in {cntlr.name}, skip it")
                continue
            if "Normal" == row.msg_type and row.msg_id is not None and row.direction == "S":
                msg_id = row.msg_id.rstrip('x')
                if "Cycle" == row.send_type:
                    if int(row.cycle_time) < 100:
                        cycle_10ms_count += 1
                        send_10ms_content_sub = """    {{{msg_id}, {obj}, {send_time}, {cycle_time}, {dlc}, {msg_name}_{can_tag}.Data}},
"""
                        send_10ms_content.append(send_10ms_content_sub.format(
                            msg_id = msg_id,
                            obj = g_can_fbcm_obj[cntlr],
                            send_time = 0,
                            cycle_time = row.cycle_time,
                            dlc = row.msg_length,
                            msg_name = row.msg_name,
                            can_tag = g_can_file_info[cntlr].can_tag
                        ))
                    else:
                        cycle_100ms_count += 1
                        send_100ms_content_sub = """    {{{msg_id}, {obj}, {send_time}, {cycle_time}, {dlc}, {msg_name}_{can_tag}.Data}},
"""
                        send_100ms_content.append(send_100ms_content_sub.format(
                            msg_id = msg_id,
                            obj = g_can_fbcm_obj[cntlr],
                            send_time = 0,
                            cycle_time = row.cycle_time,
                            dlc = row.msg_length,
                            msg_name = row.msg_name,
                            can_tag = g_can_file_info[cntlr].can_tag
                        ))
                else:
                    condition_count += 1
                    if "Event" == row.send_type:
                        condition_type = "CAN_MESSAGE_SEND_TYPE_EVENT"
                    elif "CE" == row.send_type:
                        condition_type = "CAN_MESSAGE_SEND_TYPE_CE"
                    elif "IfActive" == row.send_type:
                        condition_type = "CAN_MESSAGE_SEND_TYPE_IFACTIVE"
                    elif "CA" == row.send_type:
                        condition_type = "CAN_MESSAGE_SEND_TYPE_CA"
                    else:
                        print(f"{row.send_type} is not supported")
                        print(row.msg_name)
                        continue
                    send_condition_content_sub = """    {{{msg_id}, {obj}, {send_time}, {cycle_time}, {fast_cycle}, {st}, &{msg_name}_{can_tag}_flag, {fast_nr}, 0, 0, {msg_delay}, {dlc}, {msg_name}_{can_tag}.Data}},
"""
                    if row.cycle_time is None:
                        c_time = 0
                    else:
                        c_time = row.cycle_time
                    if row.fast_cycle is None:
                        if "Event" == row.send_type:
                            f_cycle = 20 # event default
                        else:
                            f_cycle = 0
                    else:
                        f_cycle = row.fast_cycle
                    if row.fast_nr is None:
                        if "Event" == row.send_type:
                            f_nr = 3 # event default
                        else:
                            f_nr = 0
                    else:
                        f_nr = row.fast_nr
                    if row.msg_delay is None:
                        m_delay = 0
                    else:
                        m_delay = row.msg_delay
                    send_condition_content.append(send_condition_content_sub.format(
                        msg_id = msg_id,
                        obj = g_can_fbcm_obj[cntlr],
                        send_time = 0,
                        cycle_time = c_time,
                        fast_cycle = f_cycle,
                        st = condition_type,
                        fast_nr = f_nr,
                        msg_delay = m_delay,
                        dlc = row.msg_length,
                        msg_name = row.msg_name,
                        can_tag = g_can_file_info[cntlr].can_tag
                    ))

    send_10ms_contents.append(send_10ms_content_front)
    send_10ms_contents.append("".join(send_10ms_content))
    send_10ms_contents.append(send_content_back)
    send_contents.append("".join(send_10ms_contents))

    send_100ms_contents.append(send_100ms_content_front)
    send_100ms_contents.append("".join(send_100ms_content))
    send_100ms_contents.append(send_content_back)
    send_contents.append("".join(send_100ms_contents))

    send_condition_contents.append(send_condition_content_front)
    send_condition_contents.append("".join(send_condition_content))
    send_condition_contents.append(send_content_back)
    send_contents.append("".join(send_condition_contents))
    final_send_content = "".join(send_contents)

    final_send_content = "".join(send_contents)

    now_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    # Generate can_table.h
    try:
        with open(g_generated_path + "/can_table.h", 'w') as f:
            headle_content = g_can_send_table_h_text_front.format(
                ddd2 = now_time,
                cycle_10ms_count = cycle_10ms_count,
                cycle_100ms_count = cycle_100ms_count,
                condition_count = condition_count
            )
            f.write(headle_content)
    except Exception as e:
        print("Error:", e)
    # Generate can_table.c
    try:
        with open(g_generated_path + "/can_table.c", 'w') as f:
            c_content = g_can_send_table_c_text_front.format(
                ddd2 = now_time
            )
            f.write(c_content)
            f.write(final_send_content)
    except Exception as e:
        print("Error:", e)

# Create rte file
def create_direction_common_file():
    if not os.path.exists(g_rte_path):
            os.makedirs(g_rte_path)
    else:
        shutil.rmtree(g_rte_path)
        os.makedirs(g_rte_path)
    os.makedirs(g_rte_path + '/inc')
    os.makedirs(g_rte_path + '/src')

    # Create rte can common file
    now_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    try:
        with open(g_rte_path + "/inc/Rte_Can_Common.h", 'w') as f:
            can_common_text_front_content = g_can_common_text_front.format(
                ddd2 = now_time
            )
            f.write(can_common_text_front_content)
    except Exception as e:
        print("Error:", e)

# Find and parse can comm matrix file
def find_and_parse_can_comm_matrix_file():
    martix_files = os.listdir(g_matrix_path)

    # Filter files whose names contain "FBCM"
    martix_file_names = [f for f in martix_files if f.endswith('.xlsx') and any(tag in f for tag in ['FBCM_A_', 'FBCM_B_', 'FBCM_C_', 'FBCM_P_'])]
    print(martix_file_names)

    # Handle each file
    for filename in martix_file_names:
        if '_A_' in filename:
            g_can_file_info[Controller.CanController_ACAN].can_tag = "ACAN"
            parse_can_commm_matrix_file(g_matrix_path + '/' + filename, Controller.CanController_ACAN)
        elif '_B_' in filename:
            g_can_file_info[Controller.CanController_BCAN].can_tag = "BCAN"
            parse_can_commm_matrix_file(g_matrix_path + '/' + filename, Controller.CanController_BCAN)
        elif '_C_' in filename:
            g_can_file_info[Controller.CanController_CCAN].can_tag = "CCAN"
            parse_can_commm_matrix_file(g_matrix_path + '/' + filename, Controller.CanController_CCAN)
        elif '_P_' in filename:
            g_can_file_info[Controller.CanController_PCAN].can_tag = "PCAN"
            parse_can_commm_matrix_file(g_matrix_path + '/' + filename, Controller.CanController_PCAN)

# print can matrix by send type
def print_can_matrix_by_send_type():
    cntles = list(Controller)
    for cntle in cntles[:4]:
        print(f"\nThis flow is for {g_can_file_info[cntle].can_tag}:")
        print(f"{'Msg Name':<{25}}", \
          f"{'Msg Type':<{10}}", \
          f"{'Msg ID':<{15}}", \
          f"{'Send Type':<{10}}", \
          f"{'Cycle Time':<{10}}", \
          f"{'Frame Type':<{20}}", \
          f"{'BRS':<{5}}", \
          f"{'Len':<{5}}", \
          f"{'F Cycle':<{10}}", \
          f"{'F Nr':<{5}}", \
          f"{'Delay':<{5}}", \
          f"{'Dir':<{5}}")
        for content in g_can_comm_matrix[cntle]:
            if "S" == content.direction:
                continue
            print(f"{'' if content.msg_name is None else content.msg_name:<{25}}", \
                  f"{'' if content.msg_type is None else content.msg_type:<{10}}", \
                  f"{'' if content.msg_id is None else content.msg_id:<{15}}", \
                  f"{'' if content.send_type is None else content.send_type:<{10}}", \
                  f"{'' if content.cycle_time is None else content.cycle_time:<{10}}", \
                  f"{'' if content.frame_format is None else content.frame_format:<{20}}", \
                  f"{'' if content.brs is None else content.brs:<{5}}", \
                  f"{'' if content.msg_length is None else content.msg_length:<{5}}", \
                  f"{'' if content.fast_cycle is None else content.fast_cycle:<{10}}", \
                  f"{'' if content.fast_nr is None else content.fast_nr:<{5}}", \
                  f"{'' if content.msg_delay is None else content.msg_delay:<{5}}", \
                  f"{'' if content.direction is None else content.direction:<{5}}")
# Main Function
if __name__ == "__main__":
    create_direction_common_file()
    find_and_parse_can_comm_matrix_file()
    # print_can_matrix_by_send_type()
    generate_can_matrix_report_table()
    generate_can_matrix_send_table()
